﻿/*
 * 此操作基类实现方式优先级如下
 * 1.Linq查询
 * 2.HCQ查询
 * 3.HQL查询
 * 4.原生SQL查询
 */

/*
 * 基础行为：
 * 增：Save
 * 删：Delete
 * 改：Update
 * 查：Query
 * 批量：Batch
 */

//session.Merge();
//DetachedCriteria detachedCriteria.GetExecutableCriteria(session);

using NHibernate;
using NHibernate.Criterion;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace IceZero.DataStore
{
    /// <summary>
    /// 操作基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public partial class DataStoreBase<T> where T : class, new()
    {

        /// <summary>
        /// 添加对象
        /// </summary>
        /// <typeparam name="IdType">Id的值类型</typeparam>
        /// <param name="obj">添加对象</param>
        /// <returns>主键值(id)</returns>
        public object Save(T obj)
        {
            object id = default;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                id = session.Save(obj);
            });
            return id;
        }

        /// <summary>
        /// 添加对象
        /// </summary>
        /// <typeparam name="IdType">Id的值类型</typeparam>
        /// <param name="obj">添加对象</param>
        /// <returns>主键值(id)</returns>
        public IdType Save<IdType>(T obj)
        {
            IdType id = default;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                id = (IdType)session.Save(obj);
            });
            return id;
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public void Delete(T obj)
        {
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                session.Delete(obj);
            });
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public void Delete<T>(object id)
        {
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                var obj = session.Get<T>(id);
                if (obj == null)
                {
                    return;
                }
                session.Delete(obj);
            });
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public void Delete<T>(string id)
        {
            Delete<T>((object)id);
        }

        /// <summary>
        /// 删除对象
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public void Delete<T>(int id)
        {
            Delete<T>((object)id);
        }



        /// <summary>
        /// 
        /// </summary>
        /// <param name="hql"></param>
        /// <param name="paramsAction"></param>
        /// <returns></returns>
        public int DeleteByHQL(string hql, IDictionary parameters)
        {
            int effectCount = 0;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                var query = session.CreateQuery(hql);
                SetQueryParameters(query, parameters);
                effectCount = query.ExecuteUpdate();
            });
            return effectCount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hql"></param>
        /// <param name="paramsAction"></param>
        /// <returns></returns>
        public int DeleteByHQL(string hql, Action<IQuery> paramsAction)
        {
            int effectCount = 0;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                var query = session.CreateQuery(hql);
                //query.SetParameter();
                //query.SetParameterList();
                paramsAction(query);
                effectCount = query.ExecuteUpdate();
            });
            return effectCount;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public int DeleteAll<T>()
        {
            int effectCount = 0;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                effectCount = session.Delete($"from {typeof(T).Name}");
            });
            return effectCount;
        }


        /// <summary>
        /// 更新对象
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="lockObj"></param>
        public void Update(T obj, bool lockObj = false)
        {
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                if (lockObj)
                {
                    session.Lock(obj, LockMode.Upgrade);
                }
                session.Update(obj);
            });
        }

        /// <summary>
        /// 更新对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public void Update(object id, T obj, bool lockObj = false)
        {
            if (!Exist(id)) { return; }
            Update(obj, lockObj);
        }

        public int UpdateByHQL(string hql, Action<IQuery> paramsAction)
        {
            int effectCount = 0;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                var query = session.CreateQuery(hql);
                //query.SetParameter();
                //query.SetParameterList();
                paramsAction(query);
                effectCount = query.ExecuteUpdate();
            });
            return effectCount;
        }

        /// <summary>
        /// 添加对象
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>主键值(id)</returns>
        public void SaveOrUpdate(T obj)
        {
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                session.SaveOrUpdate(obj);
            });
        }

        /// <summary>
        /// 根据 id 查找值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public T QueryById(int id)
        {
            T obj = null;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                obj = session.Get<T>(id);
            });
            return obj;
        }

        /// <summary>
        /// 根据 id 查找值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public T QueryById(string id)
        {
            T obj = null;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                obj = session.Get<T>(id);
            });
            return obj;
        }

        /// <summary>
        /// 根据 id 查找值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public T QueryById(object id)
        {
            T obj = null;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                obj = session.Get<T>(id);
            });
            return obj;
        }

        /// <summary>
        /// 查找所有的数据,仅数据量小的时候用，大了会很慢
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public List<T> QueryAll()
        {
            List<T> list = new List<T>();
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                list = session.Query<T>().ToList();
            });
            return list;
        }

        /// <summary>
        /// 查询一条数据
        /// </summary>
        /// <param name="predicate">查询条件，使用 Restrictions(.Eq)、Order(.Asc)构建</param>
        /// <returns></returns>
        /// <example>
        /// where 条件
        /// Criterion 规则列表（单数）
        /// Criteria 规则列表（复数）
        /// Restrictions 约束规则，如 Restrictions.Eq("Id", "1"); Lt Gt
        /// Expression 约束规则,已经半弃用，应该用 Restrictions 代替，如 Expression.Eq("Id"
        /// Order 指定排序规则, 如 Order.Asc("id");
        /// Projections 投影，指用一些聚合函数，如 Projections.Count Projections.Avg
        /// </example>
        public T QueryOne(Func<List<ICriterion>, List<ICriterion>> predicate)
        {
            List<ICriterion> expressions = new List<ICriterion>();
            expressions = predicate(expressions);
            ICriteria criteria = null;
            T result = default;
            NHibernateHelper.UseSession(session =>
            {
                criteria = session.CreateCriteria(typeof(T));
                expressions.ForEach(expression => criteria.Add(expression));
                result = criteria.SetFirstResult(0).SetMaxResults(1).UniqueResult<T>();
            });

            return result;
        }

        /// <summary>
        /// 根据某个字段查询数据，一般是通过唯一值查询
        /// </summary>
        /// <param name="predicate">查询条件，使用Restrictions(.Eq)、Order(.Asc)构建</param>
        /// <returns></returns>
        public T QueryOne(string propertyName, object value)
        {
            ICriteria criteria = null;
            T result = default;
            NHibernateHelper.UseSession(session =>
            {
                criteria = session.CreateCriteria<T>();
                criteria.Add(Restrictions.Eq(propertyName, value));
                result = criteria.SetFirstResult(0).SetMaxResults(1).UniqueResult<T>();
            });
            return result;

        }
        /// <summary>
        /// 根据条件查询数据
        /// </summary>
        /// <param name="predicate">查询条件，使用Restrictions(.Eq)、Order(.Asc)构建</param>
        /// <returns></returns>
        public List<T> QueryListBy(Func<List<ICriterion>, List<ICriterion>> predicate)
        {
            List<ICriterion> expressions = new List<ICriterion>();
            expressions = predicate(expressions);
            ICriteria criteria = null;
            List<T> result = default;
            NHibernateHelper.UseSession(session =>
            {
                criteria = session.CreateCriteria(typeof(T));
                expressions.ForEach(expression => criteria.Add(expression));
                result = criteria.List<T>().ToList();
            });
            return result;
        }

        /// <summary>
        /// 根据某个字段查询数据，一般是通过唯一值查询
        /// </summary>
        /// <param name="predicate">查询条件，使用Restrictions(.Eq)、Order(.Asc)构建</param>
        /// <returns></returns>
        public List<T> QueryListBy(string propertyName, object value)
        {
            ICriteria criteria = null;
            List<T> result = default;
            NHibernateHelper.UseSession(session =>
            {
                criteria = session.CreateCriteria<T>();
                criteria.Add(Restrictions.Eq(propertyName, value));
                result = criteria.List<T>().ToList();
            });
            return result;
        }

        /// <summary>
        /// 批量添加对象
        /// </summary>
        /// <param name="objs"></param>
        /// <returns></returns>
        public void BatchSave(params T[] objs)
        {
            NHibernateHelper.UseSessionWithTransactionWatchRawSql(session =>
            {
                session.SetBatchSize(objs.Length > 100 ? 100 : objs.Length);
                foreach (var obj in objs)
                {
                    session.Save(obj);
                }
            });
        }

        /// <summary>
        /// 批量添加对象
        /// </summary>
        /// <param name="objs"></param>
        /// <returns></returns>
        public void BatchSave(List<T> objs)
        {
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                foreach (var obj in objs)
                {
                    session.Save(obj);
                }
            });
        }

        /// <summary>
        /// 判断对象是否存在
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool Exist(object id)
        {
            var isExist = false;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                var obj = session.Get<T>(id);
                isExist = obj != null;
            });
            return isExist;
        }

        /// <summary>
        /// 获取对象数量
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>主键值</returns>
        public int Count()
        {
            int count = 0;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                count = session.Query<T>().Count();
            });
            return count;
        }

        /// <summary>
        /// HQL 方式查询
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns>查询结果</returns>
        public IList QueryByHQL(string queryString)
        {
            IList result = null;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                result = session.CreateQuery(queryString).List();
            });
            return result;
        }

        /// <summary>
        /// 原生 SQL 查询
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns>查询结果</returns>
        public ISQLQuery QueryBySQL(string queryString)
        {
            ISQLQuery result = null;
            NHibernateHelper.UseSessionWithTransaction(session =>
            {
                result = session.CreateSQLQuery(queryString);
            });
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <param name="parameters"></param>
        private static void SetQueryParameters(IQuery query, IDictionary parameters)
        {
            if (parameters == null)
            {
                return;
            }

            foreach (var key in parameters.Keys)
            {
                var value = parameters[key];
                switch (value)
                {
                    case object[] objects:
                        query.SetParameterList(key.ToString(), objects);
                        break;
                    case ICollection collection:
                        query.SetParameterList(key.ToString(), collection);
                        break;
                    default:
                        query.SetParameter(key.ToString(), parameters[key]);
                        break;
                }
            }
        }
    }
}
